package com.mall.b2c.service.impl;

import static com.mall.b2c.Constants.ORDER_EXPIRE_TIME;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;
import javax.persistence.LockModeType;

import com.mall.b2c.bean.BrandBean;
import com.mall.b2c.domain.store.StoreDomain;
import com.mall.b2c.service.*;
import com.mall.common.bean.Order;
import com.mall.common.domain.component.PaymentLogDomain;
import com.mall.common.util.DateHelper;
import net.sf.json.JSONObject;

import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Sets;
import com.mall.b2c.bean.PayInfo;
import com.mall.b2c.dao.CartItemDao;
import com.mall.b2c.dao.MemberDao;
import com.mall.b2c.dao.OrderDao;
import com.mall.b2c.domain.delivery.DeliveryMethodDomain;
import com.mall.b2c.domain.goods.GoodsDomain;
import com.mall.b2c.domain.member.MemberDomain;
import com.mall.b2c.domain.member.PaymentDetailDomain;
import com.mall.b2c.domain.member.ReceiverDomain;
import com.mall.b2c.domain.order.CartItemDomain;
import com.mall.b2c.domain.order.OrderDomain;
import com.mall.b2c.domain.order.OrderItemDomain;
import com.mall.b2c.domain.order.OrderLogDomain;
import com.mall.b2c.domain.order.VouchersDomain;
import com.mall.b2c.enums.DetailType;
import com.mall.b2c.enums.LogType;
import com.mall.b2c.enums.OrderItemType;
import com.mall.b2c.enums.OrderStatus;
import com.mall.b2c.enums.PayStatus;
import com.mall.b2c.enums.ShipStatus;
import com.mall.b2c.plugin.order.IOrderPayEvent;
import com.mall.b2c.plugin.order.OrderPayPluginBundle;
import com.mall.b2c.plugin.payment.IPaymentEvent;
import com.mall.b2c.plugin.payment.PaymentPluginBundle;
import com.mall.b2c.util.DictionaryUtils;
import com.mall.b2c.util.SerialNumberUtil;
import com.mall.b2c.util.SettingUtils;
import com.mall.common.bean.Pager;
import com.mall.common.domain.component.ComponentDomain;
import com.mall.common.domain.component.PaymentTypeDomain;
import com.mall.common.enums.PayType;
import com.mall.common.exception.NoticeException;
import com.mall.common.hibernate.Finder;
import com.mall.common.plugin.IPlugin;
import com.mall.common.service.ComponentService;
import com.mall.common.service.impl.BaseServiceImpl;


/**
 * Service实现类 - 订单
 * @author 
 */
@Service("b2cOrderService")
@Transactional(readOnly=true)
public class OrderServiceImpl extends BaseServiceImpl<OrderDomain, Long> implements OrderService {
	@Resource private CartItemDao cartItemDao;
	@Resource private OrderDao orderDao;
	@Resource private MemberDao memberDao;
	@Resource private OrderLogService orderLogService;
	@Resource private ReceiverService receiverService;
	@Resource private DeliveryMethodService deliveryMethodService;
	@Resource private OrderItemService orderItemService;
	@Resource private GoodsService goodsService;
	@Resource private VouchersService vouchersService;
	@Resource private ComponentService componentService;
	@Resource private PaymentDetailService paymentDetailService;
	@Resource private OrderPayPluginBundle orderPayPluginBundle;
	@Resource private PaymentPluginBundle paymentPluginBundle;
	@Resource
	private IntergralService intergralService;
	@Resource
	private StoreService storeService;

	@Resource
	public void setBaseDao(OrderDao orderDao) { 
		super.setBaseDao(orderDao); 
	}




	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public String createOrder(Long storeId, Long memberId, Long[] cartItemIds,
			Integer payType, Long receiverId, Long deliveryMethodId,
			String postscript, Boolean isInvoice, Integer invoiceType,
			String invoiceTitle) {
		if(cartItemIds == null){
			throw new NoticeException("购买商品不存在");
		}
		OrderDomain order = createOrder(storeId, memberId, payType, receiverId, deliveryMethodId, postscript, isInvoice, invoiceType, invoiceTitle);
		Finder finder = Finder.create("from CartItemDomain bean where bean.cart.member.id = :memberId and bean.id in (:itemIds)");
		finder.setParam("memberId", memberId);
		finder.setParamList("itemIds", cartItemIds);
		List<CartItemDomain> list = finder.findHQLList();
		if(list.size() < cartItemIds.length){
			throw new NoticeException("购买商品有部分不在购物车中");
		}
		BigDecimal totalWeight = BigDecimal.ZERO;
		BigDecimal total = BigDecimal.ZERO;

		Set<OrderItemDomain> items = order.getOrderItems();
		if(CollectionUtils.isEmpty(items)){
			items = Sets.newHashSet();
		}
		for(CartItemDomain item : list){
			cartItemDao.lock(item, LockModeType.PESSIMISTIC_WRITE);
			GoodsDomain goods = item.getGoods();
			if(goods.getIsMarketable() == null
					|| !goods.getIsMarketable()){
				throw new NoticeException("购买商品已下架");
			}
			if(goods.getStock() == null
					|| goods.getStock() < item.getNum()){
				throw new NoticeException("商品库存不足");
			}
			OrderItemDomain orderItem = new OrderItemDomain();
			orderItem.setGoods(goods);
			orderItem.setImage(goods.getImage_default());
			orderItem.setItemType(OrderItemType.normal);
			orderItem.setSalePrice(goods.getPrice());
			orderItem.setOrder(order);
			orderItem.setWeight(goods.getWeight());
			orderItem.setProductCode(goods.getCode());
			orderItem.setProductName(goods.getName());
			orderItem.setQuantity(item.getNum());
			orderItem.setSpecification(goods.getSpec());
			orderItemService.persist(orderItem);

			total = total.add(orderItem.getSubtotal());
			if(goods.getWeight() != null){
				totalWeight = totalWeight.add(goods.getWeight().multiply(new BigDecimal(item.getNum())));
			}
			items.add(orderItem);
			//删除购物车项
			cartItemDao.remove(item);
		}
		order.setShipFee(deliveryMethodService.calShipFee(receiverId, deliveryMethodId, memberId, totalWeight));
		order.setTotalAmount(total.add(order.getShipFee()));
		update(order);


		//TODO erp交互
		return order.getOrderNo();
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void payCash(Long memberId, String orderNo) {
		OrderDomain order = getOrderByMemberId(memberId, orderNo);


		if (order == null) {
			throw new NoticeException("订单不存在");
		}
		//余额支付更新销售数量
		if (!PayType.cashOnDelivery.equals(order.getPayType())) {
			throw new NoticeException("支付方式错误");
		}

		MemberDomain member = memberDao.find(memberId);
		if (member == null) {
			throw new NoticeException("会员不存在");
		}
		BigDecimal deposit = member.getDeposit();
		BigDecimal total = order.getTotalAmount();
		if (total.compareTo(deposit) > 0) {
			throw new NoticeException("余额不足，请选择其他支付方式");
		}
		PaymentDetailDomain paymentDetail = new PaymentDetailDomain();
		paymentDetail.setPaymentNo(SerialNumberUtil.buildPaymentSn());
		paymentDetail.setDetailType(DetailType.pay);
		paymentDetail.setAmount(total.negate());
		paymentDetail.setBalance(member.getDeposit());
		paymentDetail.setOperator(member.getUsername());
		paymentDetail.setMember(member);
		paymentDetail.setTradeNo(order.getOrderNo());
		paymentDetail.setRemarks(order.getOrderInfo());
		paymentDetail.setDealId(order.getOrderNo());
		paymentDetail.setPaymentTypeName("余额支付");


		paymentDetailService.persist(paymentDetail);
		memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
		member.setDeposit(deposit.subtract(total));
		order.setPayStatus(PayStatus.pay);
		order.setOrderStatus(OrderStatus.waitSellerSendGoods);

		updateGoodsSaleCount(order.getOrderItems());

		memberDao.merge(member);
		//计算积分
		intergralService.grantGoodsIntergral(memberId, order);

	}

	@Transactional(propagation = Propagation.REQUIRED)
	public OrderDomain createOrder(Long storeId, Long memberId, Integer payType,
			Long receiverId, Long deliveryMethodId, String postscript,
			Boolean isInvoice, Integer invoiceType, String invoiceTitle){
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(payType == null){
			throw new NoticeException("请选择付款方式");
		}
		if(payType >= PayType.values().length){
			throw new NoticeException("请选择正确付款方式");
		}
		if(receiverId == null){
			throw new NoticeException("请选择收货地址");
		}
		if(deliveryMethodId == null){
			throw new NoticeException("请选择配送方式");
		}

		
		MemberDomain member = memberDao.find(memberId);
		if(member == null){
			throw new NoticeException("会员不存在");
		}
		ReceiverDomain receiver = receiverService.getReceiver(receiverId, memberId);
		if(receiver == null){
			throw new NoticeException("收货地址不存在");
		}
		DeliveryMethodDomain method = deliveryMethodService.find(deliveryMethodId);
		if(method == null){
			throw new NoticeException("收配送方式不存在");
		}

		if(storeId == null) {
			throw new NoticeException("当前门店不存在，请重新选择门店！");
		}

		StoreDomain store = storeService.find(storeId);
		if(store == null){
			throw new NoticeException("当前门店不存在，请重新选择门店！");
		}

		OrderDomain order = new OrderDomain();
		order.setAddress(receiver.getAddress());
		order.setAreaId(receiver.getArea().getId());
		order.setAreaName(receiver.getArea().getFull_name());
		order.setConsignee(receiver.getName());
		order.setDeliveryMethod(method);
		order.setInvoiceTitle(invoiceTitle);
		order.setInvoiceType(invoiceType);
		order.setIsDelete(false);
		order.setIsInvoice(isInvoice);
		order.setMember(member);
		order.setContact(receiver.getContact());
		order.setOrderNo(SerialNumberUtil.buildOrderNo());
		order.setStore(store);
		if(payType == PayType.cashOnDelivery.ordinal()){
			order.setPayType(PayType.cashOnDelivery);
			order.setOrderStatus(OrderStatus.waitSellerSendGoods);
			order.setPaymentTypeName(DictionaryUtils.getEnumName(PayType.cashOnDelivery));
		} else if (payType == PayType.wftalipaysm.ordinal()) {
			order.setExpired(DateUtils.addMinutes(new Date(), ORDER_EXPIRE_TIME));
			order.setOrderStatus(OrderStatus.waitBuyerPay);
			order.setPayType(PayType.wftalipaysm);
			order.setPaymentTypeName(DictionaryUtils.getEnumName(PayType.wftalipaysm));
		} else if (payType == PayType.wftweixinsm.ordinal()) {
			order.setExpired(DateUtils.addMinutes(new Date(), ORDER_EXPIRE_TIME));
			order.setOrderStatus(OrderStatus.waitBuyerPay);
			order.setPayType(PayType.wftweixinsm);
			order.setPaymentTypeName(DictionaryUtils.getEnumName(PayType.wftweixinsm));
		} else {
			order.setExpired(DateUtils.addMinutes(new Date(), ORDER_EXPIRE_TIME));
			order.setOrderStatus(OrderStatus.waitBuyerPay);
			order.setPayType(PayType.onlinePayment);
			order.setPaymentTypeName(DictionaryUtils.getEnumName(PayType.onlinePayment));
		}
		order.setPayStatus(PayStatus.unpay);
		order.setPostscript(postscript);
		order.setShipStatus(ShipStatus.unpick);
		order.setZipCode(receiver.getZipCode());
		persist(order);
		
		//日志
		OrderLogDomain orderlog = new OrderLogDomain();
		orderlog.setLogText("生成订单");
		orderlog.setLogType(LogType.create);
		orderlog.setOperatorType("客户");
		orderlog.setOperator(member.getUsername());
		orderlog.setOrder(order);
		orderLogService.persist(orderlog);
		return order;
	}

	@Override
	public JSONObject checkGoods(Long memberId, Long goodsId, Integer num) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(goodsId == null){
			throw new NoticeException("商品不存在");
		}
		if(num == null || num <= 0){
			throw new NoticeException("购买数量不正确");
		}
		GoodsDomain goods = goodsService.find(goodsId);
		if(goods == null){
			throw new NoticeException("商品不存在");
		}
		if(goods.getIsMarketable() == null
				|| !goods.getIsMarketable()){
			throw new NoticeException("购买商品已下架");
		}
		if(goods.getStock() == null
				|| goods.getStock() < num){
			throw new NoticeException("商品库存不足");
		}

		BigDecimal weight = BigDecimal.ZERO;

		if(goods.getWeight() != null){
			weight = weight.add(goods.getWeight().multiply(new BigDecimal(num)));
		}

		JSONObject jObj = new JSONObject();
		jObj.put("receivers", receiverService.getRecerverList(memberId));
		jObj.put("weight", weight);
		return jObj;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public String buyNow(Long storeId, Long memberId, Long goodsId, Integer num,
			Integer payType, Long receiverId, Long deliveryMethodId,
			String postscript, Boolean isInvoice, Integer invoiceType,
			String invoiceTitle) {
		if(goodsId == null){
			throw new NoticeException("商品不存在");
		}
		if(num == null || num <= 0){
			throw new NoticeException("购买数量不正确");
		}
		OrderDomain order = createOrder(storeId, memberId, payType, receiverId, deliveryMethodId, postscript, isInvoice, invoiceType, invoiceTitle);
		GoodsDomain goods = goodsService.find(goodsId);
		if(goods.getIsMarketable() == null
				|| !goods.getIsMarketable()){
			throw new NoticeException("购买商品已下架");
		}
		if(goods.getStock() == null
				|| goods.getStock() < num){
			throw new NoticeException("商品库存不足");
		}
		OrderItemDomain orderItem = new OrderItemDomain();
		orderItem.setGoods(goods);
		orderItem.setImage(goods.getImage_default());
		orderItem.setItemType(OrderItemType.normal);
		orderItem.setSalePrice(goods.getPrice());
		orderItem.setWeight(goods.getWeight());
		orderItem.setOrder(order);
		orderItem.setProductCode(goods.getCode());
		orderItem.setProductName(goods.getName());
		orderItem.setQuantity(num);
		orderItem.setSpecification(goods.getSpec());
		orderItemService.persist(orderItem);

		BigDecimal weight = goods.getWeight();
		if(weight == null){
			weight = BigDecimal.ZERO;
		}
		order.setShipFee(deliveryMethodService.calShipFee(receiverId, deliveryMethodId, memberId, weight.multiply(BigDecimal.valueOf(num))));
		order.setTotalAmount(orderItem.getSubtotal().add(order.getShipFee()));
		update(order);

		//余额支付更新销售数量
		if(PayType.cashOnDelivery.equals(order.getPayType())){
			Set<OrderItemDomain> items = Sets.newHashSet();
			updateGoodsSaleCount(items);
		}

		//TODO erp交互
		return order.getOrderNo();
	}
	
	@Override
	public OrderDomain getOrderByMemberId(Long memberId, String orderNo) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(StringUtils.isBlank(orderNo)){
			throw new NoticeException("订单不存在");
		}
		Finder finder = Finder.create("from OrderDomain bean where bean.member.id=:memberId and bean.orderNo = :orderNo");
		finder.setParam("memberId", memberId);
		finder.setParam("orderNo", orderNo);
		Object obj = finder.findUniqueByHQL();
		if(obj == null){
			throw new NoticeException("订单不存在");
		}
		return (OrderDomain) obj;
	}

	@Override
	public OrderDomain getOrderByTradeNo(String tradeNo, Long memberId) {
		if(memberId == null){
			throw new NoticeException("会员不存在");
		}
		if(StringUtils.isBlank(tradeNo)){
			throw new NoticeException("订单不存在");
		}
		Finder finder = Finder.create("from OrderDomain bean where bean.tradeNo = :tradeNo and bean.member.id =:memberId");
		finder.setParam("tradeNo", tradeNo);
		finder.setParam("memberId", memberId);
		Object obj = finder.findUniqueByHQL();
		return obj == null?null : (OrderDomain)obj;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public JSONObject checkPayInfo(PayInfo payInfo) {
		JSONObject jObj = new JSONObject();
		OrderDomain order = getOrderByMemberId(payInfo.getMemberId(), payInfo.getOrderNo());
		if(order == null){
			throw new NoticeException("订单不存在");
		}
		if(order.getPayStatus() != PayStatus.unpay){
			jObj.put("isFinish", true);
			return jObj;
		}
		if(order.getOrderStatus() != OrderStatus.waitBuyerPay){
			throw new NoticeException("当前订单状态不能进行在线支付");
		}
		if(order.getPayType() == PayType.cashOnDelivery){
			throw new NoticeException("当前订单不支持在线支付");
		}
		BigDecimal total = order.getAmount();
		if(total == null){
			throw new NoticeException("订单金额不正确");
		}
		BigDecimal shipFee = order.getShipFee();
		BigDecimal goodsAmount = total;
		if(shipFee != null){
			goodsAmount = goodsAmount.subtract(shipFee);
		}
		List<IPlugin> pluginList = orderPayPluginBundle.getPluginList();
		for(IPlugin plugin : pluginList){
			IOrderPayEvent orderPayEvent = (IOrderPayEvent) plugin;
			total = orderPayEvent.beforePay(order, order.getMember(), goodsAmount, shipFee, payInfo);
			if(total == null){
				throw new NoticeException(orderPayEvent.getPayError());
			}
		}
		BigDecimal cash = order.getCash();
		if(cash.signum() > 0){//需要支付现金
			String domain = SettingUtils.get().getUrlBuff(true).toString();
			String bankInfo = payInfo.getBankInfo();
			String pickupUrl = domain + "/order/showResult/" + payInfo.getMemberId() + ".jhtml";
			String receiveUrl = domain + "/order/payResult/" + payInfo.getMemberId() + ".jhtml";
			if(StringUtils.isBlank(bankInfo)){
				throw new NoticeException("请选择支付方式!");
			}
			if(StringUtils.isBlank(pickupUrl) || StringUtils.isBlank(receiveUrl)){
				throw new NoticeException("支付参数出错，请联系客服");
			}
			if(!bankInfo.startsWith("106")){
				throw new NoticeException("支付方式不存在");
			}
			JSONObject config = SettingUtils.getDictionaryConfig(bankInfo);
			if(config == null || config.get("component") == null){
				throw new NoticeException("支付方式配置有误!");
			}
			ComponentDomain component = componentService.getComponent(config.getString("component"));
			if(component == null){
				throw new NoticeException("系统出错，订单无法支付!");
			}
			pluginList = paymentPluginBundle.getPluginList();
			for(IPlugin plugin : pluginList){
				if (plugin.getId().equals(component.getComponentId())) {
					IPaymentEvent pay = (IPaymentEvent) plugin;
					String result;
					try {
						Object obj = config.get("code");
						if(obj == null){
							obj = "";
						}
						result = pay.onPay(component, order, obj.toString(), pickupUrl, receiveUrl);
						update(order);
					} catch (Exception e) {
						throw new NoticeException("订单无法支付,请联系客服!");
					}
					jObj.put("form", result);
					return jObj;
				}
			}
			throw new NoticeException("订单无法支付,请联系客服!");
		} else {//不需要现金支付或余额支付，则直接完成支付
			pay(payInfo.getOrderNo(), null, null);
			jObj.put("isFinish", true);
			return jObj;
		}
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public JSONObject checkWftPayInfo(PayInfo payInfo) {
		JSONObject jObj = new JSONObject();
		OrderDomain order = getOrderByMemberId(payInfo.getMemberId(), payInfo.getOrderNo());
		if(order == null){
			throw new NoticeException("订单不存在");
		}
		if(order.getPayStatus() != PayStatus.unpay){
			jObj.put("isFinish", true);
			return jObj;
		}
		if(order.getOrderStatus() != OrderStatus.waitBuyerPay){
			throw new NoticeException("当前订单状态不能进行扫描支付");
		}
		if(order.getPayType() == PayType.cashOnDelivery){
			throw new NoticeException("当前订单不支持扫描");
		}
		BigDecimal total = order.getAmount();
		if(total == null){
			throw new NoticeException("订单金额不正确");
		}
		BigDecimal shipFee = order.getShipFee();
		BigDecimal goodsAmount = total;
		if(shipFee != null){
			goodsAmount = goodsAmount.subtract(shipFee);
		}
		List<IPlugin> pluginList = orderPayPluginBundle.getPluginList();
		for(IPlugin plugin : pluginList){
			IOrderPayEvent orderPayEvent = (IOrderPayEvent) plugin;
			total = orderPayEvent.beforePay(order, order.getMember(), goodsAmount, shipFee, payInfo);
			if(total == null){
				throw new NoticeException(orderPayEvent.getPayError());
			}
		}
		BigDecimal cash = order.getCash();
		if(cash.signum() > 0){//需要支付现金
			String domain = SettingUtils.get().getUrlBuff(true).toString();
			String bankInfo = payInfo.getBankInfo();
			String pickupUrl = domain + "/order/showResult/" + payInfo.getMemberId() + ".jhtml";
			String receiveUrl = domain + "/order/smPayResult/" + payInfo.getMemberId() + ".jhtml";
			if (StringUtils.isBlank(bankInfo) || !bankInfo.startsWith("108")) {
				throw new NoticeException("支付方式不存在");
			}
			JSONObject config = SettingUtils.getDictionaryConfig(bankInfo);
			if (config == null || config.get("component") == null) {
				throw new NoticeException("支付方式配置有误!");
			}
			ComponentDomain component = componentService.getComponent(config.getString("component"));
			if(component == null){
				throw new NoticeException("系统出错，订单无法支付!");
			}
			pluginList = paymentPluginBundle.getPluginList();
			for(IPlugin plugin : pluginList){
				if (plugin.getId().equals(component.getComponentId())) {
					IPaymentEvent pay = (IPaymentEvent) plugin;
					String result;
					try {
						result = pay.onPay(component, order, bankInfo, pickupUrl, receiveUrl);
						update(order);
					} catch (Exception e) {
						throw new NoticeException("订单无法支付,请联系客服!");
					}
					jObj.put("params", result);
					return jObj;
				}
			}
			throw new NoticeException("订单无法支付,请联系客服!");
		} else {//不需要现金支付或余额支付，则直接完成支付
			pay(payInfo.getOrderNo(), null, null);
			jObj.put("isFinish", true);
			return jObj;
		}
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void pay(String tradeNo, PaymentTypeDomain paymentType, String dealId) {
		OrderDomain order = get("tradeNo", tradeNo);


		if(order == null){
			throw new NoticeException("交易编号不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		if(order.getOrderStatus() != OrderStatus.waitBuyerPay){
			throw new NoticeException("交易状态不正确");
		}
		MemberDomain member = order.getMember();
		memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
		List<IPlugin> pluginList = orderPayPluginBundle.getPluginList();
		for(IPlugin plugin : pluginList){
			IOrderPayEvent orderPayEvent = (IOrderPayEvent) plugin;
			String error = orderPayEvent.afterPay(order, member);
			if(StringUtils.isNotBlank(error)){
				throw new NoticeException(error);
			}
		}
		order.setExpired(null);
		order.setPayStatus(PayStatus.pay);
		order.setOrderStatus(OrderStatus.waitSellerSendGoods);
		order.setFeeDate(new Date());
		order.setTradeNo(tradeNo);
		order.setPaymentType(paymentType);
		if(paymentType != null){
			order.setPaymentTypeName(paymentType.getName());
		}
		update(order);
		BigDecimal total = BigDecimal.ZERO;
		if(order.getDeposit() != null){
			total = total.add(order.getDeposit());
		}
		if(order.getCash() != null){
			total = total.add(order.getCash());
		}
		if(total.signum() > 0){
			PaymentDetailDomain paymentDetail = new PaymentDetailDomain();
			paymentDetail.setPaymentNo(SerialNumberUtil.buildPaymentSn());
			paymentDetail.setDetailType(DetailType.pay);
			paymentDetail.setAmount(total.negate());
			paymentDetail.setBalance(member.getDeposit());
			paymentDetail.setOperator(member.getUsername());
			paymentDetail.setMember(member);
			paymentDetail.setTradeNo(tradeNo);
			paymentDetail.setRemarks(order.getOrderInfo());
			if(paymentType != null){
				paymentDetail.setPaymentTypeName(paymentType.getName());
			}
			paymentDetail.setDealId(dealId);
			paymentDetailService.persist(paymentDetail);
		}
		memberDao.merge(member);

		//生成付款单
		VouchersDomain vouchers = new VouchersDomain();
		vouchers.setAmount(order.getAmount());
		vouchers.setDeposit(order.getDeposit());
		vouchers.setCash(order.getCash());
		vouchers.setOperate(member.getUsername());
		vouchers.setPayType(order.getPayType());
		if(paymentType != null){
			vouchers.setPaymentMethod(paymentType.getName());
		}
		vouchers.setMember(member);
		vouchers.setOrder(order);
		vouchersService.persist(vouchers);

		//更新商品销售数量
		updateGoodsSaleCount(order.getOrderItems());
		
		//订单日志保存
		OrderLogDomain log = new OrderLogDomain();		
		log.setLogText("订单支付");
		log.setOrder(order);		
		log.setOperator(member.getUsername());
		log.setLogType(LogType.pay);
		log.setOperatorType("客户");
		orderLogService.persist(log);
		//计算积分
		intergralService.grantGoodsIntergral(member.getId(), order);
	}
	
	/**
	 * 维护商品销售记录
	 */
	@Transactional(propagation=Propagation.REQUIRED)
	public void updateGoodsSaleCount(Set<OrderItemDomain> items){
		if(!CollectionUtils.isEmpty(items)){
			for(OrderItemDomain item : items){
				GoodsDomain goods = item.getGoods();
				if(goods != null){
					goods.setSales(goods.getSales() == null
							? 1
							: goods.getSales() + 1);
					goodsService.update(goods);
				}
			}
		}
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void pickup(Long orderId, String operator) {
		OrderDomain order = this.find(orderId);
		if(order == null){
			 throw new NoticeException("订单不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		if(order.getIsExpired()){
			throw new NoticeException("订单已过期");
		}
		if(!order.getOrderStatus().equals(OrderStatus.waitSellerSendGoods) 
				&&  !order.getShipStatus().equals(ShipStatus.unpick) ){
			throw new NoticeException("当前订单状态无法进行此操作");
		}

		if(order.getAllOrderItemToRefundAndFinished()){
			throw new NoticeException("当前订单项已全部退款");
		}

		order.setShipStatus(ShipStatus.unsend);
		this.update(order);
		
		//日志
		OrderLogDomain orderlog = new OrderLogDomain();
		orderlog.setLogText("订单拣货");
		orderlog.setLogType(LogType.pick);
		orderlog.setOperatorType("系统");
		orderlog.setOperator(operator);
		orderlog.setOrder(order);
		orderLogService.persist(orderlog);
		
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void complete(Long orderId, String operator) {
		OrderDomain order = this.get("id",orderId);
		if(order == null){
			 throw new NoticeException("订单不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		if(order.getOrderStatus() != OrderStatus.waitBuyerConfirmGoods && !order.getAllOrderItemToRefundAndFinished()){
			throw new NoticeException("当前订单状态不能执行此操作");
		}
		order.setOrderStatus(OrderStatus.tradeFinished);
		order.setExpired(null);
		orderDao.merge(order);
		
		//保存支付成功日志
		OrderLogDomain log = new OrderLogDomain();		
		log.setLogText("订单完成");
		log.setOrder(order);		
		log.setOperator(operator);
		log.setLogType(LogType.complete);
		log.setOperatorType("系统");
		orderLogService.persist(log);
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void cancel(String orderNo, String operator) {
		OrderDomain order = get("orderNo", orderNo);
		if(order == null){
			throw new NoticeException("订单不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		OrderStatus orderStatus = order.getOrderStatus();
		if(!orderStatus.equals(OrderStatus.waitBuyerPay)){
			throw new NoticeException("当前订单状态不能执行此操作");
		}
		if(!order.getPayStatus().equals(PayStatus.unpay)){
			throw new NoticeException("订单已支付不能进行取消操作");
		}
		if(order.getShipStatus().equals(ShipStatus.send)){
			throw new NoticeException("该订单已发货不能进行取消操作");
		}
		order.setOrderStatus(OrderStatus.tradeClosed);
		order.setExpired(null);
		this.update(order);
		
		//订单日志保存
		OrderLogDomain log = new OrderLogDomain();		
		log.setLogText("订单取消");
		log.setOrder(order);		
		log.setOperator(operator);
		log.setLogType(LogType.cancel);
		log.setOperatorType( "系统");
		orderLogService.persist(log);
		
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void delete(Long[] ids, String operator) {
		List<OrderDomain> orderList = get(ids);
		for(OrderDomain order : orderList){
			orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
			order.setIsDelete(true);
			update(order);
			
			//订单日志保存
			OrderLogDomain log=new OrderLogDomain();		
			log.setLogText("删除订单");
			log.setOrder(order);		
			log.setOperator(operator);
			log.setLogType(LogType.delete);
			log.setOperatorType("系统");
			orderLogService.persist(log);
		}
	}

	@Override
	public Pager getOrderPager(String keyword, Long memberId, Date startDate, Date endDate, Integer orderStatus, Integer pagerNumber) {
		Pager pager = new Pager();
		pager.setPageSize(10);
		if(pagerNumber != null && pagerNumber > 0){
			pager.setPageNumber(pagerNumber);
		}
		if(memberId == null){
			return pager;
		}
		Finder finder = Finder.create("select new com.mall.b2c.bean.OrderBean(bean) from OrderDomain bean where bean.member.id = :memberId");
		finder.setParam("memberId", memberId);
		if(StringUtils.isNotBlank(keyword)){
			finder.append(" and bean.orderNo = :keyword");
			finder.setParam("keyword", keyword);
		}
		if(startDate != null){
			finder.append(" and bean.createDate >= :startDate");
			finder.setParam("startDate", startDate);
		}
		if(endDate != null){
			finder.append(" and bean.createDate <= :endDate");
			finder.setParam("endDate", endDate);
		}
		if(orderStatus != null && orderStatus >=0){
			OrderStatus[] statuses = OrderStatus.values();
			if(statuses.length >= orderStatus + 1){
				finder.append(" and bean.orderStatus = :orderStatus");
				finder.setParam("orderStatus", statuses[orderStatus]);
			}
		}
		finder.append(" and bean.isDelete = false order by bean.createDate desc");
		return this.findByPagerForHessian(pager, finder);
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void offlinePay(String orderNo, String operator, String memo) {
		OrderDomain order = get("orderNo", orderNo);
		if(order == null){
			throw new NoticeException("订单不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		if(order.getIsExpired()){
			throw new NoticeException("订单已过期");
		}
		if(order.getPayStatus() != null
				&& order.getPayStatus() != PayStatus.unpay){
			throw new NoticeException("订单已支付");
		}
		order.setExpired(null);
		//TODO 订单支付类型为在线支付通过后台手动支付需更改订单状态
		if(order.getPayType() == PayType.onlinePayment 
				&& order.getOrderStatus() == OrderStatus.waitBuyerPay){
			updateGoodsSaleCount(order.getOrderItems());
			order.setOrderStatus(OrderStatus.waitSellerSendGoods);
		}
		order.setPayStatus(PayStatus.pay);
		order.setFeeDate(new Date());
		update(order);
		
		MemberDomain member = order.getMember();
		memberDao.lock(member, LockModeType.PESSIMISTIC_WRITE);
		//生成付款单
		VouchersDomain vouchers = new VouchersDomain();
		vouchers.setAmount(order.getAmount());
		vouchers.setDeposit(order.getDeposit());
		vouchers.setCash(order.getCash());
		vouchers.setMember(member);
		vouchers.setOperate(operator);
		vouchers.setPayType(order.getPayType());
		vouchers.setOrder(order);
		vouchers.setPaymentMethod("线下支付");
		vouchers.setMemo(memo);
		vouchersService.persist(vouchers);
		
		//订单日志保存
		OrderLogDomain log = new OrderLogDomain();		
		log.setLogText("订单支付");
		log.setOrder(order);		
		log.setOperator(operator);
		log.setLogType(LogType.pay);
		log.setOperatorType("系统");
		orderLogService.persist(log);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void cancelOrder(String orderNo, Long memberId) {
		OrderDomain order = this.getOrderByMemberId(memberId, orderNo);
		if(order == null){
			throw new NoticeException("该订单不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		if(order.getOrderStatus() != OrderStatus.waitBuyerPay){
			throw new NoticeException("当前订单状态不能取消订单");
		}
		order.setOrderStatus(OrderStatus.tradeClosed);
		order.setExpired(null);
		this.update(order);

		OrderLogDomain log = new OrderLogDomain();
		log.setLogText("取消订单");
		log.setLogType(LogType.cancel);
		log.setOperator(order.getMember().getUsername());
		log.setOperatorType("客户");
		log.setOrder(order);
		orderLogService.persist(log);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void deleteOrder(String orderNo, Long memberId) {
		OrderDomain order = this.getOrderByMemberId(memberId, orderNo);
		if(order == null){
			throw new NoticeException("该订单不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		if(order.getIsDelete()){
			throw new NoticeException("该订单已删除");
		}
		if(order.getOrderStatus() != OrderStatus.tradeFinished
				&& order.getOrderStatus() != OrderStatus.tradeClosed){
			throw new NoticeException("当前订单状态不能删除订单");
		}
		order.setIsDelete(true);
		this.update(order);

		OrderLogDomain log = new OrderLogDomain();
		log.setLogText("删除订单");
		log.setLogType(LogType.delete);
		log.setOperator(order.getMember().getUsername());
		log.setOperatorType("客户");
		log.setOrder(order);
		orderLogService.persist(log);

	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void confirmReceive(String orderNo, Long memberId) {
		OrderDomain order = this.getOrderByMemberId(memberId, orderNo);
		if(order == null){
			throw new NoticeException("该订单不存在");
		}
		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		if(order.getOrderStatus() != OrderStatus.waitBuyerConfirmGoods){
			throw new NoticeException("当前订单状态不能确认收货");
		}
		order.setOrderStatus(OrderStatus.tradeFinished);
		this.update(order);

		OrderLogDomain log = new OrderLogDomain();
		log.setLogText("确认收货");
		log.setLogType(LogType.receiver);
		log.setOperator(order.getMember().getUsername());
		log.setOperatorType("客户");
		log.setOrder(order);
		orderLogService.persist(log);
		}
}
